package org.ns.framework.datasource.config;


import java.util.Map;
import java.util.function.Supplier;

import javax.sql.DataSource;

import org.ns.framework.datasource.mybatis.MybatisDataSourceInjector;
import org.ns.framework.datasource.redis.RedisBeanInjector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DataSourceConfiguration implements InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;
    
	private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);

    @Bean
    DataSourceConfig dataSourceConfig() {
        return new DataSourceConfig();
    }

    @Bean
    RedisBeanInjector redisBeanInjector() {
        return new RedisBeanInjector();
    }

    @Bean
    MybatisDataSourceInjector mybatisDataSourceInjector() {
        return new MybatisDataSourceInjector();
    }
    
    @Bean
    MybatisConfigurationManage mybatisConfigurationManage() {
    	return new MybatisConfigurationManage();
    };
    

    
    @Override
    public void afterPropertiesSet() throws Exception {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext;
        DataSourceConfig dataSourceConfig = dataSourceConfig();
        Map<String, Supplier<DataSource>> dataSources = dataSourceConfig.toDataSources();

        for (Map.Entry<String, Supplier<DataSource>> entry : dataSources.entrySet()) {
            String datasourceName = entry.getKey();
            Supplier<DataSource> dataSource = entry.getValue();

            if (registry.containsBeanDefinition(datasourceName)) {
                throw new RuntimeException("beanName 冲突："  + datasourceName +"[数据源名称与某Bean名称冲突、无法注册到IOC容器]");
            }


            BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DataSourceFactory.class)
                    .addConstructorArgValue(DataSource.class)
                    .addConstructorArgValue(dataSource)
                    .setLazyInit(true)
                    .getBeanDefinition();
            registry.registerBeanDefinition(datasourceName, beanDefinition);
        }

        for (Map.Entry<String, Redis> entry : dataSourceConfig.getRedis().entrySet()) {
            String datasourceName = entry.getKey();
            Redis redis = entry.getValue();
            Supplier<Redis> redisSource = ()->redis;

            if (registry.containsBeanDefinition(datasourceName)) {
                throw new RuntimeException("beanName 冲突："  + datasourceName +"[数据源名称与某Bean名称冲突、无法注册到IOC容器]");
            }

            BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DataSourceFactory.class)
                    .addConstructorArgValue(Redis.class)
                    .addConstructorArgValue(redisSource)
                    .setLazyInit(true)
                    .getBeanDefinition();
            registry.registerBeanDefinition(datasourceName, beanDefinition);
        }
       
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
